JavaScript数据结构与算法

349次阅读
没有评论

共计 7737 个字符,预计需要花费 20 分钟才能阅读完成。

数组结构

参考:http://8.129.6.198/post/173/

栈结构

栈 (stack) 又名堆栈,是一种运算受限的线性表,限定仅在表尾进行插入和删除操作。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素称作进栈,从一个栈删除元素称作出栈。

特点:后进先出,即 Last in First out (LIFO)。

class Stack {#items = [] //# 符号声明私有属性,ES13 新特性

  pop() {return this.#items.pop() // 出栈
  }

  push(data) {return this.#items.push(data) // 进栈
  }

  peek() {return this.#items.at(-1) // 栈顶
  }

  isEmpty() {return this.#items.length === 0}

  size() {return this.#items.length}

  clear() {this.#items = []
  }

  toString() {return this.#items.join(" ")
  }
}

// 十进制转 2 8 16 进制
function convert(decNumber, base) {let remStack = new Stack()
  let number = decNumber
  let string = ""
  let baseString = "0123456789ABCDEF"

  while (number > 0) {remStack.push(number % base)
    number = Math.floor(number / base)
  }

  while (!remStack.isEmpty()) {string += baseString[remStack.pop()]
  }

  return string
}

convert(500, 16)

队列结构

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾(入队),进行删除操作的端称为队头(出队)。队列中没有元素时,称为空队列。

特点:先进先出,即 First in First out(FIFO)。

封装与应用

class Queue {#items = {}
  #lowCount = 0
  #count = 0

  dequeue() {if (this.isEmpty()) {return undefined}

    let res = this.#items[this.#lowCount]
    delete this.#items[this.#lowCount]
    this.#lowCount++
    return res // 出队
  }

  enqueue(data) {this.#items[this.#count] = data // 入队
    this.#count++
  }

  front() {return this.#items[this.#lowCount] // 队头
  }

  isEmpty() {return this.size() === 0
  }

  size() {return this.#count - this.#lowCount}

  clear() {this.#items = {}
    this.#count = 0
    this.#lowCount = 0
  }

  toString() {
    let str = ""
    for (let i = this.#lowCount; i < this.#count; i++) {str += `${this.#items[i]} `
    }

    return str
  }
}

// 击鼓传花游戏
function game(list, num) {let queue = new Queue()
  for (let i = 0; i < list.length; i++) {queue.enqueue(list[i])
  }

  while (queue.size() > 1) {for (let i = 0; i < num; i++) {queue.enqueue(queue.dequeue())
    }

    console.log(queue.dequeue(), " 淘汰了 ")
  }

  return queue.dequeue() + " 获胜 "}

game([" 张三 ", " 李四 ", " 王五 ", " 赵六 ", " 孙七 "], 7)

双端队列

class DeQueue {#items = {}
  #lowCount = 0 // 队头索引
  #count = 0

  removeFront() {if (this.isEmpty()) {return undefined}

    let res = this.#items[this.#lowCount]
    delete this.#items[this.#lowCount]
    this.#lowCount++

    return res
  }

  removeBack() {if (this.isEmpty()) {return}

    this.#count--
    const res = this.#items[this.#count]
    delete this.#items[this.#count]

    return res
  }

  addFront(data) {if (this.isEmpty()) {this.addBack(data)
    } else {if (this.#lowCount > 0) {
        this.#lowCount--
        this.#items[this.#lowCount] = data
      } else {
        // #lowCount=0
        for (let i = this.#count; i > 0; i--) {this.#items[i] = this.#items[i - 1]
        }
      }
    }
  }

  addBack(data) {this.#items[this.#count] = data
    this.#count++
  }

  peekFront() {return this.#items[this.#lowCount]
  }

  peekBack() {return this.#items[this.#count - 1]
  }

  isEmpty() {return this.size() === 0
  }

  size() {return this.#count - this.#lowCount}

  clear() {this.#items = {}
    this.#count = 0
    this.#lowCount = 0
  }

  toString() {
    let str = ""
    for (let i = this.#lowCount; i < this.#count; i++) {str += `${this.#items[i]} `
    }

    return str
  }
}

// 回文字符串检查
function test(str) {const lowstr = str.toLocaleLowerCase().split(" ").join("")
  let dequeue = new DeQueue()

  for (let i = 0; i < lowstr.length; i++) {dequeue.addBack(lowstr[i])
  }

  let isEqual = true
  while (dequeue.size() > 1) {if (dequeue.removeFront() != dequeue.removeBack()) {
      isEqual = false
      break
    }
  }

  return isEqual
}

test(" 上海自来水来自海上 ")

链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点 (链表中每一个元素称为结点) 组成,结点可以在运行时动态生成。每个结点包括两个部分: 一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

链表的特点

  1. 插入、删除数据效率高 O(1)级别 (只需更改指针指向即可),随机访问效率低 O(n) 级别(需要从链头至链尾进行遍历)
  2. 和数组相比,内存空间消耗更大,因为每个存储数据的节点都需要额外的空间存储后继指针。

单链表

每个节点只包含一个指针,即后继指针。

class Node {constructor(element) {
    this.element = element
    this.next = null
  }
}

class LinkedList {constructor() {
    this.count = 0
    this.head = null
  }

  push(element) {const node = new Node(element)

    if (this.head === null) {this.head = node} else {
      let current = this.head

      while (current.next !== null) {current = current.next}

      current.next = node
    }

    this.count++
  }

  getNodeAt(index) {if (index >= 0 && index < this.count) {
      let node = this.head
      for (let i = 0; i < index; i++) {node = node.next}

      return node
    }

    return
  }

  // 指定位置删除
  removeAt(index) {if (index >= 0 && index < this.count) {
      let current = this.head
      if (index === 0) {this.head = this.head.next} else {let previous = this.getNodeAt(index - 1)
        current = previous.next
        previous.next = current.next
      }

      this.count--
      return current.element
    }

    return
  }

  equalFn(a, b) {return JSON.stringify(a) === JSON.stringify(b)
  }

  indexOf(element) {
    let current = this.head
    for (let i = 0; i < index; i++) {if (this.equalFn(element, current.element)) {return i}
      current = current.next
    }

    return -1
  }

  // 指定元素删除
  remove(element) {const index = this.indexOf(element)
    return this.removeAt(index)
  }

  insert(element, index) {if (index >= 0 && index <= this.count) {const node = new Node(element)
      if (index === 0) {
        const current = this.head
        node.next = current
        this.head = node
      } else {const previous = this.getNodeAt(index - 1)
        const current = previous.next

        node.next = current
        previous.next = node
      }

      this.count++
      return true
    }

    return false
  }

  isEmpty() {return this.size() === 0
  }

  size() {return this.count}

  getHead() {return this.head}
}

// 回文字符串检查
function test(str) {const lowstr = str.toLocaleLowerCase().split(" ").join("")
  let sll = new LinkedList()

  for (let i = 0; i < lowstr.length; i++) {sll.push(lowstr[i])
  }

  let isEqual = true
  while (sll.size() > 1) {if (sll.removeAt(0) !== sll.removeAt(sll.size() - 1)) {
      isEqual = false
      break
    }
  }

  return isEqual
}

test(" 上海自来水来自海上 ")

击鼓传花游戏使用单链表:

// 击鼓传花游戏
function game(list, num) {let queue = new LinkedList()
  for (let i = 0; i < list.length; i++) {queue.push(list[i])
  }

  while (queue.size() > 1) {for (let i = 0; i < num; i++) {queue.push(queue.removeAt(0))
    }

    console.log(queue.removeAt(0), " 淘汰了 ")
  }

  return queue.removeAt(0) + " 获胜 "
}

game([" 张三 ", " 李四 ", " 王五 ", " 赵六 ", " 孙七 "], 7)

十进制转 2 8 16 进制:

// 十进制转 2 8 16 进制
function convert(decNumber, base) {let remStack = new LinkedList()
  let number = decNumber
  let string = ""
  let baseString = "0123456789ABCDEF"

  while (number > 0) {remStack.push(number % base)
    number = Math.floor(number / base)
  }

  while (!remStack.isEmpty()) {string += baseString[remStack.removeAt(remStack.size() - 1)]
  }

  return string
}

convert(500, 16)

双链表

class DoublyNode extends Node {constructor(element) {super(element)
    this.prev = null
  }
}

class DoublyLinkedList extends LinkedList {constructor() {super()
    this.tail = null
  }

  push(element) {const node = new DoublyNode(element)
    if (this.head === null) {
      this.head = node
      this.tail = node
    } else {
      this.tail.next = node
      node.prev = this.tail
      this.tail = node
    }

    this.count++
  }

  remove(element) {const index = this.indexOf(element)
    return this.removeAt(index)
  }

  insert(element, index) {if (index >= 0 && index <= this.count) {const node = new DoublyNode(element)
      let current = this.head
      if (index === 0) {if (this.head === null) {
          this.head = node
          this.tail = node
        } else {
          node.next = this.head
          this.head.prev = node
          this.head = node
        }
      } else if (index === this.count) {
        current = this.tail
        current.next = node
        node.prev = current
        this.tail = node
      } else {const previous = this.getNodeAt(index - 1)
        current = previous.next

        node.next = current
        current.prev = node
        previous.next = node
        node.prev = previous
      }

      this.count++
      return true
    }

    return false
  }

  removeAt(index) {if (index >= 0 && index < this.count) {
      let current = this.head
      if (index === 0) {
        this.head = current.next
        if (this.count === 1) {this.tail = null} else {this.head.prev = null}
      } else if (index === this.count - 1) {
        current = this.tail
        this.tail = current.prev
        this.tail.next = null
      } else {let previous = this.getNodeAt(index - 1)
        current = previous.next
        previous.next = current.next
        current.next.prev = previous
      }

      this.count--
      return current.element
    }

    return
  }

  getHead() {return this.head}

  getTail() {return this.tail}
}

循环链表

循环链表和链表之间唯一的区别在于,最后一个元素指向下一个元素的指针 (tail.next) 不是 undefined,而是指向第一个元素(head)。

class CircularLinkedList extends LinkedList {constructor() {super()
  }

  push(element) {const node = new Node(element)
    let current
    if (this.head === null) {this.head = node} else {current = this.getNodeAt(this.size() - 1)
      current.next = node
    }

    node.next = this.head
    this.count++
  }

  insert() {if (index >= 0 && index <= this.count) {const node = new Node(element)
      let current = this.head
      if (index === 0) {if (this.head === null) {
          this.head = node
          node.next = this.head
        } else {
          node.next = current
          this.head = node

          current = this.getNodeAt(this.size() - 1)
          current.next = this.head
        }
      } else {const previous = this.getNodeAt(index - 1)
        node.next = previous.next
        previous.next = node
      }

      this.count++
      return true
    }

    return false
  }

  removeAt(index) {if (index >= 0 && index < this.count) {
      let current = this.head
      if (index === 0) {if (this.size() === 1) {this.head = null} else {let last = this.getNodeAt(this.size() - 1)
          this.head = this.head.next
          last.next = this.head
        }
      } else {const previous = this.getNodeAt(index - 1)
        current = previous.next
        previous.next = current.next
      }

      this.count--
      return current.element
    }

    return
  }
}

正文完
 0
阿伯手记
版权声明:本站原创文章,由 阿伯手记 于2023-08-29发表,共计7737字。
转载说明:本站原创内容,除特殊说明外,均基于 CC BY-NC-SA 4.0 协议发布,转载须注明出处与链接。
评论(没有评论)
验证码

阿伯手记

阿伯手记
阿伯手记
喜欢编程,头发渐稀;成长路上,宝藏满地
文章数
767
评论数
207
阅读量
683357
今日一言
-「
热门文章
职场救急!AI请假话术生成器:1秒定制高通过率理由

职场救急!AI请假话术生成器:1秒定制高通过率理由

超级借口 不好开口?借口交给我!智能生成工作请假、上学请假、饭局爽约、约会拒绝、邀约推辞、万能借口等各种借口理...
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
TVAPP:开源电视盒子资源库,一键打造家庭影院

TVAPP:开源电视盒子资源库,一键打造家庭影院

导语 TVAPP 是一个专为 Android TV 电视盒子用户打造的开源影音资源库,集成了影视、直播、游戏等...
巴别英语:用美剧和TED演讲轻松提升英语听力与口语

巴别英语:用美剧和TED演讲轻松提升英语听力与口语

还在为枯燥的英语学习而烦恼吗?巴别英语通过创新的美剧学习模式,让英语学习变得生动有趣。平台提供海量美剧和 TE...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
2025年12月 每日精选

2025年12月 每日精选

关于每日精选栏目 发现一些不错的资源,点击 这里 快速投稿。 12 月 26 日 .ax 顶级域 目前全球唯一...
123云盘限时福利:登录即送1个月VIP尊享权益!

123云盘限时福利:登录即送1个月VIP尊享权益!

🎁  零成本体验 20T 超大空间与会员加速通道 🎉 活动亮点 登录即送:无需任何复杂操作,登录账号直接领取 ...
最新评论
阿伯手记 阿伯手记 发了:https://aboss.top/moments/1064
吴蛋蛋 吴蛋蛋 快发小年快乐
吴蛋蛋 吴蛋蛋 Ask4Me,这个之前看server酱接入了
15220202929 15220202929 怎么用
八对 八对 麻烦大佬更新下【堆新】的友链站名:八对星星描述:极目星视穹苍无界•足履行者大地有疆链接:https://8dui.com图标:https://cf.8dui.com/logo.webp横标:https://cf.8dui.com/logo-w.webp订阅:https://8dui.com/rss.xml
三毛笔记 三毛笔记 已添加
DUINEW DUINEW 已添加贵站,期待贵站友链~博客名称:堆新博客地址:https://duinew.com/博客描述:堆新堆新,引力向新!——堆新(DUINEW)博客头像:https://d.duinew.com/logo.webp横版头像:https://d.duinew.com/logo-w.webp博客订阅:https://duinew.com/rss.xml
hedp hedp 没看懂
bingo bingo 直接生成就可以啦,也可以添加一些选项
热评文章
夸克网盘快传助手提高非VIP下载速度

夸克网盘快传助手提高非VIP下载速度

夸克网盘限速这个大家都知道,不开会员差不多限速在几百 K。那有没有办法在合法合规途径加速下载夸克网盘呢?这里推...
Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 免费开源短网址程序,基于Fastify、Vercel和Supabase构建

Short-Link 是一款基于 Fastify、Vercel 和 Supabase 构建的 URL 缩短服务...
清华大学官方免费DeepSeek教程

清华大学官方免费DeepSeek教程

AI 领域近期最引人注目的焦点当属 DeepSeek,这款由中国创新企业深度求索研发的人工智能工具,正以开放源...
Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 在线中文姓名生成器

Chinese Name Generator 是一款在线中文姓名生成器,可在几秒内生成符合个人需求的中文名字。...
2026年2月 每日精选

2026年2月 每日精选

关于每日精选栏目 发现一些不错的资源,点击 这里 快速投稿。 2 月 17 日 国家全民健身信息服务平台 过年...
DrawLink:一键生成链接视觉卡片,提升分享点击率

DrawLink:一键生成链接视觉卡片,提升分享点击率

小贴士 :此站或已变迁,但探索不止步。我们已为您备好「类似网站」精选合集,相信其中的发现同样能为您带来惊喜。
WebRTC Screen Mirror:基于浏览器免费开源投屏神器,可实现低延迟、跨平台屏幕共享

WebRTC Screen Mirror:基于浏览器免费开源投屏神器,可实现低延迟、跨平台屏幕共享

WebRTC Screen Mirror 是一款基于 WebRTC 技术的在线屏幕共享工具,它利用浏览器内置的...